package com.example.springboottest.example.io.redirect.appserver.nio2;

import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
import sun.tools.jconsole.Worker;

import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Iterator;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * 支持多个客户端连接，均为非阻塞
 * 但是在链接服务器的时候，还是存在阻塞情况
 * AsynchronousSocketChannel channel = future.get();
 */
public class NIO2Server {
    private ExecutorService taskExecutor;
    private AsynchronousServerSocketChannel serverChannel;

    class Worker implements Callable<String> {
        private CharBuffer charBuffer;
        private CharsetDecoder decoder = Charset.defaultCharset().newDecoder();
        private AsynchronousSocketChannel channel;

        public Worker(AsynchronousSocketChannel channel) {
            this.channel = channel;
        }

        @Override
        public String call() throws Exception {
            System.out.println(Thread.currentThread().getName() + "\t开始工作");
            final ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
            //读取请求
            while (channel.read(buffer).get() != -1) {
                buffer.flip();
                charBuffer = decoder.decode(buffer);
                String request = charBuffer.toString().trim();
                System.out.println("客户端请求" + request);

                ByteBuffer outBuffer = ByteBuffer.wrap(("请求" + request + "收到").getBytes());
                //将响应输出到客户端
                channel.write(outBuffer).get();
                if (buffer.hasRemaining())
                    buffer.compact();
                else
                    buffer.clear();
            }
            channel.close();
            System.out.println(Thread.currentThread().getName() + "\t工作结束");
            return "ok";
        }
    }

    public void init() throws Exception {
        //创建线程池
        taskExecutor = Executors.newCachedThreadPool(Executors.defaultThreadFactory());
        //创建AsynchronousServerSocketChannel
        serverChannel = AsynchronousServerSocketChannel.open();
        if (serverChannel.isOpen()) {
            serverChannel.setOption(StandardSocketOptions.SO_RCVBUF, 4 * 1024);
            serverChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
            //绑定端口
            serverChannel.bind(new InetSocketAddress("127.0.0.1", 8080));
        } else
            throw new RuntimeException("通道未打开！");
    }

    public void start() throws Exception {
        System.out.println("等待客户端请求......");
        while (true) {
            System.out.println("while (true)");
            //接收客户端请求
            Future<AsynchronousSocketChannel> future = serverChannel.accept();
            try {
                //等待并得到请求通道
                AsynchronousSocketChannel channel = future.get();
                //提交到线程池进行请求处理
                taskExecutor.submit(new Worker(channel));
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        NIO2Server server = new NIO2Server();
        server.init();
        server.start();
    }
}
